Avoid a hang when probing the partition table on imported block
authorsos22@douglas.cl.cam.ac.uk <sos22@douglas.cl.cam.ac.uk>
Fri, 2 Dec 2005 14:16:37 +0000 (15:16 +0100)
committersos22@douglas.cl.cam.ac.uk <sos22@douglas.cl.cam.ac.uk>
Fri, 2 Dec 2005 14:16:37 +0000 (15:16 +0100)
devices.  If you export a device so the importing domain sees it as a
whole disk rather than a partition, then add_disk will try to probe
its partition table.  However, we were calling add_disk before the
device was properly connected, and then not connecting it until
add_disk had finished.  This meant that we ended up never actually
connecting the device, and any accesses to it would then hang.

Fix this by not calling add_disk until we're connected.

Signed-off-by: Steven Smith, sos22@cam.ac.uk
linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
linux-2.6-xen-sparse/drivers/xen/blkfront/block.h
linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c

index e7afc76b8e87c486cea8bfad4bf3d634088c28cf..6c9e5b64803677828dd8aa6ec3a158937b7ed2ac 100644 (file)
@@ -311,7 +311,7 @@ static void connect(struct blkfront_info *info)
        int err;
 
         if( (info->connected == BLKIF_STATE_CONNECTED) || 
-           (info->connected == BLKIF_STATE_SUSPENDED) ) 
+           (info->connected == BLKIF_STATE_SUSPENDED) )
                return;
 
        DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend);
@@ -327,16 +327,18 @@ static void connect(struct blkfront_info *info)
                                 info->xbdev->otherend);
                return;
        }
-       
+
         xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
 
        (void)xenbus_switch_state(info->xbdev, NULL, XenbusStateConnected); 
-       
+
        /* Kick pending requests. */
        spin_lock_irq(&blkif_io_lock);
        info->connected = BLKIF_STATE_CONNECTED;
        kick_pending_request_queues(info);
        spin_unlock_irq(&blkif_io_lock);
+
+       add_disk(info->gd);
 }
 
 /**
@@ -588,7 +590,6 @@ void do_blkif_request(request_queue_t *rq)
 
        while ((req = elv_next_request(rq)) != NULL) {
                info = req->rq_disk->private_data;
-
                if (!blk_fs_request(req)) {
                        end_request(req, 0);
                        continue;
index 809451aec7359eb8344650781bd4b7fd69b4d92b..3809f9067b7fa36ef039f41fd101f2872fda7889 100644 (file)
@@ -146,6 +146,9 @@ extern int blkif_revalidate(dev_t dev);
 extern void do_blkif_request (request_queue_t *rq); 
 
 /* Virtual block-device subsystem. */
+/* Note that xlvbd_add doesn't call add_disk for you: you're expected
+   to call add_disk on info->gd once the disk is properly connected
+   up. */
 int xlvbd_add(blkif_sector_t capacity, int device,
              u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
 void xlvbd_del(struct blkfront_info *info);
index 47ebba39f2ba21378aba72b8327f39eb2905c77b..d97f798e6fa6281acb36290d0146941f1d48574c 100644 (file)
@@ -261,7 +261,6 @@ xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
        if (vdisk_info & VDISK_CDROM)
                gd->flags |= GENHD_FL_CD;
 
-       add_disk(gd);
        info->gd = gd;
 
        return 0;